package com.jungle.client;

import com.google.gson.reflect.TypeToken;
import com.jungle.client.channel.HttpClient;
import com.jungle.client.control.DraggableTableCell;
import com.jungle.client.control.RowNoTableCell;
import com.jungle.client.event.SaveEvent;
import com.jungle.client.vo.ApiMetadataVo;
import com.jungle.client.vo.DataDefinitionVo;
import javafx.beans.property.SimpleBooleanProperty;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.control.cell.CheckBoxTableCell;
import javafx.scene.input.Dragboard;
import javafx.scene.layout.GridPane;
import lombok.extern.slf4j.Slf4j;

import java.net.URL;
import java.util.List;
import java.util.ResourceBundle;

@Slf4j
public class DataDefinitionController implements Initializable {
    @FXML
    private TableView<DataDefinitionVo> tableView;
    @FXML
    private TableColumn<DataDefinitionVo, Integer> rowIndexColumn;
    @FXML
    private TableColumn<DataDefinitionVo, String> nameColumn;
    @FXML
    private TableColumn<DataDefinitionVo, String> codeColumn;
    @FXML
    private TableColumn<DataDefinitionVo, Boolean> scenarioColumn;
    @FXML
    private TableColumn<DataDefinitionVo, Boolean> requiredColumn;

    @FXML
    private GridPane dataDefinitionInfo;
    /**
     * fxml文件中，定义引入组件id，才能注入组件的controller
     */
    @FXML
    private DataDefinitionInfoController dataDefinitionInfoController;

    private final ObservableList<DataDefinitionVo> items = FXCollections.observableArrayList();

    /**
     * 传入参数数据
     */
    private DataDefinitionVo dataDefinition;

    public void initialize(URL location, ResourceBundle resources) {
        log.info("init DataDefinitionController, location:{}", location);
        // 添加保存事件过滤器
        addSaveEventFilter();
        // 绑定数据
        unionDataDefinitionInfo();
        // 监听数据变化
        dataChangeListener();

        // 拖拽到当前表格时，检查可编辑行是否最少有一条空行，如果没有则添加一行
        tableView.setOnDragOver(event -> {
            Dragboard db = event.getDragboard();
            if (db.hasContent(com.jungle.client.control.DraggableTableCell.SERIALIZED_MIME_TYPE)) {
                int size = items.size();
                if (size == 0 || items.get(size - 1).getId() != null) {
                    items.add(new DataDefinitionVo());
                }
            }
        });

        // 设置行号列
        rowIndexColumn.setCellFactory(RowNoTableCell.forTableColumn());

        // 数据名称-访问路径列
        nameColumn.setCellFactory(DraggableTableCell.forString((dataDefinitionVo, content) -> {
            if (content instanceof ApiMetadataVo metadataVo) {
                dataDefinitionVo.setApiId(metadataVo.getApiId());
                dataDefinitionVo.setName(metadataVo.getName());
            }
        }));
        // 数据编码-访问路径列
        codeColumn.setCellFactory(DraggableTableCell.forString((dataDefinitionVo, content) -> {
            if (content instanceof ApiMetadataVo metadataVo) {
                dataDefinitionVo.setApiId(metadataVo.getApiId());
                dataDefinitionVo.setCode(metadataVo.getName());
            }
        }));

        scenarioColumn.setCellValueFactory(cellData -> cellData.getValue().scenarioFlagProperty());
        scenarioColumn.setCellFactory(CheckBoxTableCell.forTableColumn(scenarioColumn));
        scenarioColumn.setEditable(false);

        requiredColumn.setCellValueFactory(cellData -> new SimpleBooleanProperty(Boolean.TRUE.equals(cellData.getValue().getRequired())));
        requiredColumn.setCellFactory(CheckBoxTableCell.forTableColumn(requiredColumn));
        requiredColumn.setEditable(false);
    }

    public void loadData(DataDefinitionVo dataDefinitionVo) {
        this.dataDefinition = dataDefinitionVo;
        if (dataDefinitionVo != null) {
            com.jungle.bfi.domain.vo.DataDefinitionVo dataDefinitionRo = DataDefinitionVo.copy(dataDefinitionVo);
            // 剔除 scenarioFlag 默认数据
            dataDefinitionRo.setScenarioFlag(null);
            HttpClient.getInstance().post("/dataDefinition/list", dataDefinitionRo).callback(new TypeToken<List<com.jungle.bfi.domain.vo.DataDefinitionVo>>() {
            }, list -> {
                items.clear();
                if (list != null && !list.isEmpty()) {
                    List<DataDefinitionVo> list1 = list.stream().map(DataDefinitionVo::from).toList();
                    items.addAll(list1);
                    tableView.refresh();
                }
            });
        }
    }

    private void addSaveEventFilter() {
        tableView.addEventFilter(SaveEvent.SAVE, event -> {
            if (event.getTarget() instanceof TableView && event instanceof SaveEvent se) {
                int rowIndex = se.getRowIndex();
                DataDefinitionVo dataDefinitionVo = items.get(rowIndex);
                log.info("save row:{}, value:{}", rowIndex, dataDefinitionVo);
                if (dataDefinition == null || dataDefinition.getApiPath() == null) {
                    log.warn("apiPath is null");
                } else if (dataDefinitionVo.getName() != null || dataDefinitionVo.getCode() != null || dataDefinitionVo.getCategoryValue() != null || dataDefinitionVo.getScenarioFlag() != null) {
                    dataDefinitionVo.setApiPath(dataDefinition.getApiPath());
                    HttpClient.getInstance().post("/dataDefinition/store", dataDefinitionVo)
                            .callback(DataDefinitionVo.class, dataItemPo -> refreshRowData(rowIndex, dataItemPo));
                }
            }
        });
    }

    private void unionDataDefinitionInfo() {
        // 添加信息保存回调处理
        dataDefinitionInfoController.addConsumer(dataDefinitionVo -> {
            if (dataDefinitionVo != null) {
                int selectedIndex = tableView.getSelectionModel().getSelectedIndex();
                refreshRowData(selectedIndex, dataDefinitionVo);
            }
        });

        tableView.setItems(items);

        // 添加表格选中监听
        tableView.getSelectionModel().selectedItemProperty().addListener((observable, oldValue, newValue) -> {
            log.info("selected:{}", newValue);
            if (newValue == null) {
                dataDefinitionInfoController.reset();
            } else {
                dataDefinitionInfoController.loadData(newValue);
            }
        });
    }

    private void dataChangeListener() {
        items.forEach(item -> item.scenarioFlagProperty().addListener((observable, oldValue, newValue) -> log.info("scenarioFlagProperty changed:{}", newValue)));
    }

    private void refreshRowData(int selectedIndex, DataDefinitionVo dataDefinitionVo) {
        if (selectedIndex >= 0) {
            items.set(selectedIndex, dataDefinitionVo);
            tableView.refresh();
        }
    }
}
